package com.atguigu.gmall.common.config.pool;


import com.atguigu.gmall.common.config.pool.properties.AppThreadPoolProperties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


@EnableConfigurationProperties(AppThreadPoolProperties.class)
//1、开启 AppThreadPoolProperties 的属性配置绑定
//2、把 AppThreadPoolProperties 放到容器中
@Configuration
public class AppThreadPoolConfiguration {


    /**
     * int corePoolSize,       核心大小
     * int maximumPoolSize,    最大大小（额外开（kat时间不用就要销毁）=最大大小-核心大小 ）
     * long keepAliveTime,     空闲时间
     * TimeUnit unit,          时间单位
     * BlockingQueue<Runnable> workQueue,    排队队列
     * ThreadFactory threadFactory,          线程工厂
     * RejectedExecutionHandler handler      拒绝策略：
     * <p>
     * 如果线程数量已经达到最大，而且队列满了。新任务再进来，利用拒绝策略进行拒绝；
     * 线上提交的任务都是要被执行的，如果线程池没满，就用线程池启动一个异步线程执行（用户感觉快）。
     * 如果线程池满了，让提交任务的当前线程，自己同步运行这个任务即可（用户感觉慢一点）。
     *
     * @return
     * @Bean标注的方法。如果有任何参数。这些参数默认都去容器中获取组件
     */
    @Primary
    @Bean
    public ThreadPoolExecutor
    corePool(AppThreadPoolProperties threadPoolProperties,
             @Value("${spring.application.name}") String applicationName) {
        //1、线程池想要对接监控平台。
        //2、监控平台自己从redis中拉取各种指标，进行可视化展示
        //3、
        return new ThreadPoolExecutor(threadPoolProperties.getCorePoolSize(),
                threadPoolProperties.getMaximumPoolSize(),
                threadPoolProperties.getKeepAliveTime(),
                TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(threadPoolProperties.getWorkQueueSize()),
                new ThreadFactory() { //线程池中所有的线程都是它new的
                    int i = 0; //单线程

                    @Override
                    public Thread newThread(Runnable r) {
                        // 分布式全线程数量限制：redis.incr(thread-count) < 100000

                        //利用层层封装完整所有功能
//                        Runnable runnable = new Runnable() {
//                            @Override
//                            public void run() { //根据cpu调度
//
//                            }
//                        };
                        Thread thread = new Thread(() -> {
                            //redis.incr("running...") 任务前置逻辑增强
                            r.run(); //跑真实任务
                            //redis.decr("running...") 任务后置逻辑增强
                        });
                        thread.setName("【" + applicationName + "】-apppool-" + (i++));
                        return thread;
                    }
                },
                new ThreadPoolExecutor.CallerRunsPolicy());
    }


    /**
     * 线上应用突然内存不足，疯狂gc？
     * - 手动降级：
     * - 熔断(系统保护机制)、降级（手动保护机制）： 效果：不能用了。
     * @param threadPoolProperties
     * @param applicationName
     * @return
     */
//    @Bean
//    public ThreadPoolExecutor
//      otherPool(AppThreadPoolProperties threadPoolProperties,
//             @Value("${spring.application.name}") String applicationName){
//        //1、线程池想要对接监控平台。
//        //2、监控平台自己从redis中拉取各种指标，进行可视化展示
//        //3、
//        return new ThreadPoolExecutor(threadPoolProperties.getCorePoolSize(),
//                threadPoolProperties.getMaximumPoolSize(),
//                threadPoolProperties.getKeepAliveTime(),
//                TimeUnit.MILLISECONDS,
//                new LinkedBlockingQueue<>(threadPoolProperties.getWorkQueueSize()),
//                new ThreadFactory() { //线程池中所有的线程都是它new的
//                    int i = 0; //单线程
//                    @Override
//                    public Thread newThread(Runnable r) {
//                        // 分布式全线程数量限制：redis.incr(thread-count) < 100000
//
//                        //利用层层封装完整所有功能
////                        Runnable runnable = new Runnable() {
////                            @Override
////                            public void run() { //根据cpu调度
////
////                            }
////                        };
//                        Thread thread = new Thread(()->{
//                            //redis.incr("running...") 任务前置逻辑增强
//                            r.run(); //跑真实任务
//                            //redis.decr("running...") 任务后置逻辑增强
//                        });
//                        thread.setName("【"+applicationName+"】-apppool-"+ (i++));
//                        return thread;
//                    }
//                },
//                new ThreadPoolExecutor.CallerRunsPolicy());
//    }
}
